/**
 * 多个“任务设置(Config)”类的功能，例如群内批量加人，都有选择企业微信的步骤。
 * 此模块实现了这方面的通用逻辑。
 */
import { type MaySuccess } from '@gnlab/utils'
import { useAsyncEffect, useRefValue } from '@gnlab/utils/env-react'
import { message } from 'antd'
import { type AccountForChoose } from '@/desktop/components/ChooseQywxs'
import services from '@/services'

/**
 * 加载此类业务专属的企业微信数据，并记录占用和离线状态
 */
interface BaseQywxForChoose {
  wxid: string
}

export interface QywxForChooseExtra {
  used: boolean // 此企业微信是否已被其他任务使用
  offline: boolean // 此企业微信是否已离线（创建任务时在线，编辑任务时离线了）
}

export function useQywxsForChoose<Q extends BaseQywxForChoose>(
  // 配置 ID，为 null 代表是新建配置（对部分业务可能字段名出不同，这里统称 configId）
  configId: number | null,

  getBaseQywxs: (configId?: number) => Promise<MaySuccess<Q[]>>,

  // 获取企业微信已绑定的配置 ID。因为不同业务的字段名不一样，需要使用者自己传入回调。
  getQywxConfigId: (qywx: Q) => number | undefined | null,
) {
  type QywxForChoose = Q & QywxForChooseExtra

  const getBaseQywxsRef = useRefValue(getBaseQywxs)
  const [qywxs, setQywxs] = useState<QywxForChoose[] | null>(null)
  useAsyncEffect(async () => {
    const [onlineWxids, qywxsRes] = await Promise.all([
      configId === null ? null : services.qywxs.getAllAccountWxids(),
      getBaseQywxsRef.current(configId ?? undefined),
    ])
    if (!qywxsRes.success) return void message.warning('企业微信列表加载失败')

    const baseQywxs = qywxsRes.data
    const usedWxids = new Set(
      baseQywxs
        .filter(qywx => {
          const qywxConfigId = getQywxConfigId(qywx)
          return (
            typeof qywxConfigId === 'number' && (configId === null || qywxConfigId !== configId)
          )
        })
        .map(info => info.wxid),
    )
    const offlineWxids = new Set(
      onlineWxids ? baseQywxs.map(v => v.wxid).filter(wxid => !onlineWxids.has(wxid)) : [],
    )

    const qywxs = baseQywxs.map(qywx => ({
      ...qywx,
      used: usedWxids.has(qywx.wxid),
      offline: offlineWxids.has(qywx.wxid),
    }))
    setQywxs(qywxs)
  }, [configId, getBaseQywxsRef])

  return qywxs
}

/**
 * 整理出 /desktop/components/ChooseQywxs 组件所需的企业微信和账号数据
 */
type BaseQywxInChoosingData = BaseQywxForChoose &
  QywxForChooseExtra & {
    accountName: string
    accountRemark: string
  }

export function useChoosingData<Q extends BaseQywxInChoosingData>(
  qywxs: Q[], // useQywxsForChoose() 提供的企业微信数据
  initialChoosed: string[], // 初始选中的 wxid 列表
  disableUsed = true, // 已被其他任务使用的企业微信是否禁止选中
  disableOffline = true, // 离线的企业微信是否禁止选中
) {
  const [choosed, setChoosed] = useState(initialChoosed)

  const choosingData = useMemo(() => {
    // 目前数据源里没有给出 accountId，用 name 代替
    const accountMap = new Map<string, AccountForChoose>()
    for (const qywx of qywxs)
      accountMap.set(qywx.accountName, {
        id: qywx.accountName,
        name: qywx.accountName,
        remark: qywx.accountRemark,
      })
    return {
      accounts: [...accountMap.values()],
      qywxs: qywxs.map(v => ({ ...v, accountId: v.accountName })),
    }
  }, [qywxs])

  const disabledWxids = useMemo(
    () =>
      new Set(
        qywxs
          .filter(v => (disableUsed && v.used) || (disableOffline && v.offline))
          .map(v => v.wxid),
      ),
    [qywxs, disableUsed, disableOffline],
  )

  return {
    choosedWxids: choosed,
    setChoosedWxids: setChoosed,
    choosingData,
    disabledWxids,
  }
}
